/*********************************************************************************
* Socks5 Proxy Main 处理
*********************************************************************************/
#include <iostream>
#include <string>
#include "framework.h"
#include "SysConfigInfo.h"

using namespace std;

/**********************************************************************************
* 全局变量，Socket句柄存放数组
**********************************************************************************/
SFW_TcpPort* conn_Array[MAX_LISTEN_NUM];

/**********************************************************************************
* 函数定义
**********************************************************************************/
int Listen();
void DoTransfor(int clientfd, int remotefd);
void debug_wait();
void dosigcld(int sig);

/**********************************************************************************
* 函数名：main
* 功能  ：主函数
* 参数  ：无
* 返回值：无
**********************************************************************************/
int main(int argc, char* argv[])
{
	int sockfd, maxfd;
	int rtn;
	int index;
	pid_t childpid;
	bool isFullConnect = false;
	
	struct sigaction sa;
	//sa.sa_handler = dosigcld;
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sigaction(SIGCLD, &sa, NULL);
	
	
	WFW_LogWriter::getMainLog()->start("/home/public/test/log/Socks5.log");
	LOG_INFO("===================================Start Appliaction ===================================");
	
	if(SystemConfigInfo::readSysConfigInfo(" <*******> ") == false)
	{
		LOG_FATAL("system config file read failure(@@@)!");
		return -1;
	}
	
	/// listen start
	sockfd = Listen();
	if(sockfd < 0)
	{
		return -1;
	}
	
	fd_set rset;
	/// loop
	while(true)
	{
		FD_ZERO(&rset);
		if(!isFullConnect)
		{
			FD_SET(sockfd, &rset);
		}
		
		maxfd = (maxfd > sockfd ? maxfd : sockfd);
		for(index = 0; index < MAX_LISTEN_NUM; index ++)
			if(NULL != conn_Array[index])
				conn_Array[index]->fdset(&rset, &maxfd);
				
		rtn = select(maxfd + 1, &rset, NULL, NULL, NULL);
		if(rtn < 0)
		{
			LOG_FATAL("socket failure(@@@)!");
			break;
		}
		
		for(index = 0; index < MAX_LISTEN_NUM; index ++)
		{
			if(NULL == conn_Array[index])
				continue;

			if(conn_Array[index]->getClientfd() != -1 && FD_ISSET(conn_Array[index]->getClientfd(), &rset) == true)
			{
				/* client => myself/remote data read ... */
				conn_Array[index]->RecvFromClient();
				
				if(conn_Array[index]->IsTcpConnectMode() && conn_Array[index]->IsEstablish())
				{
					/* fork */
					if((childpid = fork()) == 0)
					{
						/* child process */
						/* DEBUG */
						//debug_wait();
						close(sockfd);
						LOG_DEBUG("Child Open");
						DoTransfor(conn_Array[index]->getClientfd(), conn_Array[index]->getRemotefd());
						LOG_DEBUG("Child Close");
						exit(0);
					}
					
					else
					{
						/* parent process */
						conn_Array[index]->reset();
					}
				}
			}
		}

		if(FD_ISSET(sockfd, &rset) == true)
		{
			//isTooQuickly = true;
			/* client => myself : connection */
			LOG_INFO("(C) => (M) : connection");
			for(index = 0; index < MAX_LISTEN_NUM; index ++)
			{
				if(NULL == conn_Array[index])
					conn_Array[index] = new SFW_TcpPort();
				if(0 == conn_Array[index]->ClientConnect(sockfd))
					break;
			}
					
			if(index == MAX_LISTEN_NUM)
			{
				isFullConnect = true;
				LOG_FATAL("no more connection resource(@@@)!");
			}
		}		
	}
	return 0;
}

/**********************************************************************************
* 函数名：Listen
* 功能  ：启动服务器的监听
* 参数  ：无
* 返回值：监听启动成功的Socket描述符
**********************************************************************************/
int Listen()
{
	/* IPv4 only */
	int sockfd;
	sockaddr_in svrInfo;
	/* initialize */
	memset(&svrInfo, 0x00, sizeof(sockaddr_in));

	/* socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		LOG_FATAL("socket failur(@@@)!");
		return -1;
	}
	
	svrInfo.sin_family = AF_INET;
	svrInfo.sin_port = htons(SOCKS_PORT);
	svrInfo.sin_addr.s_addr = htonl(INADDR_ANY);

	/* bind */
	int rtn = bind(sockfd, (SA*)&svrInfo, sizeof(SA));
	if(rtn < 0)
	{
		LOG_FATAL("bind failure(@@@)!");
		return -2;
	}

	/* listen */
	rtn = listen(sockfd, MAX_LISTEN_NUM);
	if(rtn < 0)
	{
		LOG_FATAL("listen failure(@@@)!");
		return -3;
	}
	
	return sockfd;
}

/**********************************************************************************
* 函数名：DoTransfor
* 功能  ：启动子进程，进行Client与Remote服务器的报文转发
* 参数  ：clientfd --> 已经检查成功的Tcp模式的Client描述符
          remotefd --> Remote服务器的Socket链接描述符
* 返回值：无
**********************************************************************************/
void DoTransfor(int clientfd, int remotefd)
{
	fd_set crset;
	int maxfd;
	int rtn, rcvlen;
	char buffer[1024000];
	int buflen = 1024000;
	
	while(true)
	{
		FD_ZERO(&crset);
		FD_SET(clientfd, &crset);
		FD_SET(remotefd, &crset);
		maxfd = (clientfd > remotefd ? clientfd : remotefd);
		
		rtn = select(maxfd + 1, &crset, NULL, NULL, NULL);
		if(rtn < 0)
		{
			break;
		}
		
		if(FD_ISSET(clientfd, &crset))
		{
			if((rcvlen = read(clientfd, buffer, buflen)) <= 0)
			{
				if(rcvlen == 0)
				{
					close(clientfd);
					close(remotefd);
					break;
				}
				
				else if(errno == EAGAIN)
				{
					continue;
				}
			}
			LOG_INFO("[TCP](C) ==> (R). receive length %d", rcvlen);
			write(remotefd, buffer, rcvlen);
		}
		
		memset(buffer, 0x00, sizeof(buffer));
		if(FD_ISSET(remotefd, &crset))
		{
			if((rcvlen = read(remotefd, buffer, buflen)) <= 0)
			{				
				if(rcvlen == 0)
				{
					close(remotefd);
					close(clientfd);
					break;
				}
				
				else if(errno == EAGAIN)
				{
					continue;
				}
			}
			LOG_INFO("[TCP](C) <== (R). receive length %d", rcvlen);
			write(clientfd, buffer, rcvlen);
		}
		
		/* for next */
		memset(buffer, 0x00, sizeof(buffer));
	}
}

/**********************************************************************************
* 函数名：debug_wait
* 功能  ：★★★进程Debug用函数
* 参数  ：无
* 返回值：无
**********************************************************************************/
void debug_wait()
{
	bool isOk = false;
    while(1)
    {
        if (isOk != true)
            sleep(5);
        else
            break;
    }
}

/**********************************************************************************
* 函数名：dosigcld
* 功能  ：进程信号相应函数
* 参数  ：sig --> 信号号
* 返回值：无
**********************************************************************************/
void dosigcld(int sig)
{
	cout<<"end :"<<sig<<endl;
	/* do nothing */
}
